package com.heima.comment.service.impl;
import java.util.*;

import com.alibaba.nacos.client.utils.StringUtils;
import com.heima.comment.feign.UserFeign;
import com.heima.comment.service.CommentService;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.model.comment.dtos.CommentDto;
import com.heima.model.comment.dtos.CommentLikeDto;
import com.heima.model.comment.dtos.CommentSaveDto;
import com.heima.model.comment.pojos.ApComment;
import com.heima.model.comment.pojos.ApCommentLike;
import com.heima.model.comment.vo.ApCommentVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.pojos.ApUser;
import com.heima.utils.threadlocal.AppThreadLocalUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.stream.Collectors;

/**
 * @作者 itcast
 * @创建日期 2021/2/21 10:06
 **/
@Service
@Slf4j
public class CommentServiceImpl implements CommentService {
    @Autowired
    UserFeign userFeign;

    @Autowired
    GreenTextScan greenTextScan;

    @Autowired
    MongoTemplate mongoTemplate;

    @Override
    public ResponseResult saveComment(CommentSaveDto dto) {
        log.info("saveComment params is {}",dto);
        // 1. 检查参数 (文章id  评论内容不能大于140字符)
        if(dto == null || dto.getArticleId() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if(StringUtils.isEmpty(dto.getContent()) || dto.getContent().length() > 140){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"评论内容不能大于140个字符");
        }
        // 2. 检查是否登录 , 远程查询用户信息
        ApUser user = AppThreadLocalUtils.getUser();
        if(user == null || user.getId() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN,"登录之后才能评论");
        }
        ApUser userInfo = userFeign.findUserById(Long.valueOf(user.getId()));
        if(userInfo == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN,"获取用户信息失败");
        }
        // 3. 阿里云检测评论内容是否违规
        try {
            Map map = greenTextScan.greeTextScan(dto.getContent());
            String suggestion = (String)map.get("suggestion");
            if("block".equals(suggestion)){
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"评论有违规，请注意你的言辞");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("阿里云审核文本内容出现错误  {}",e.getCause());
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR,"内容审核出现异常");
        }
        // 4. 保存评论信息
        ApComment apComment = new ApComment();
        apComment.setAuthorId(userInfo.getId());
        apComment.setAuthorName(userInfo.getName());
        apComment.setEntryId(dto.getArticleId());
        apComment.setType((short)0);
        apComment.setContent(dto.getContent());
        apComment.setImage(userInfo.getImage());
        apComment.setLikes(0);
        apComment.setReply(0);
        apComment.setFlag((short)0);
        apComment.setCreatedTime(new Date());
        apComment.setUpdatedTime(new Date());
        mongoTemplate.save(apComment);
        return ResponseResult.okResult();
    }


    @Resource(name = "likesLock")
    RLock likesLock; // 分布式锁对象


    @Override
    public ResponseResult like(CommentLikeDto dto) {
        // 1. 检查参数 (评论ID  operation 是否是 0 或 1  )
        if(dto == null || dto.getCommentId() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if(dto.getOperation() == null || ( dto.getOperation()!=0 && dto.getOperation() != 1)){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //    判断用户是否登录
        ApUser user = AppThreadLocalUtils.getUser();
        if(user == null || user.getId() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        likesLock.lock();
        ApComment apComment;

        try {
            // 2. 根据评论ID评论信息查询出来
            apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);
            if(apComment == null){
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"该评论不存在");
            }
            if(dto.getOperation() == 0){
                // 3. 如果点赞方式为 0 (点赞)
                // 3.1 将评论的点赞数+1
                apComment.setLikes(apComment.getLikes() + 1);
                mongoTemplate.save(apComment); // 修改该评论
                // 3.2 保存评论点赞信息
                ApCommentLike apCommentLike = new ApCommentLike();
                apCommentLike.setAuthorId(user.getId());
                apCommentLike.setCommentId(dto.getCommentId());
                apCommentLike.setOperation((short)0);
                mongoTemplate.save(apCommentLike);
            }else {
                // 4. 如果点赞方式为 1 (取消点赞)
                // 4.1 将评论的点赞数-1
                apComment.setLikes(apComment.getLikes()==0 ? 0 : apComment.getLikes() - 1);
                mongoTemplate.save(apComment); // 修改该评论
                // 4.2 删除评论点赞信息
                Query query = Query.query(Criteria.where("commentId").is(dto.getCommentId()).and("authorId").is(user.getId()));
                mongoTemplate.remove(query,ApCommentLike.class);
            }
        } finally {
            likesLock.unlock();
        }
        // 5. 返回结果 ( likes )    {   data : {  "likes" : 21 }}
        Map map = new HashMap();
        map.put("likes",apComment.getLikes());
        return ResponseResult.okResult(map);
    }

    @Override
    public ResponseResult findByArticleId(CommentDto dto) {
        // 1. 检查参数 （文章id  最小时间  分页:20 ）
        if(dto == null || dto.getArticleId() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if(dto.getMinDate() == null){
            dto.setMinDate(new Date());
        }
        int size = 20; // 默认分页长度20

        // 2. 查询评论列表
        // ( 文章ID = ？  and  创建时间 < minDate   使用创建时间降序排序  取前20条数据)
        Query query = Query.query(Criteria.where("entryId").is(dto.getArticleId())
                .and("createdTime").lt(dto.getMinDate()))
                .with(Sort.by(Sort.Direction.DESC,"createdTime"))
                .limit(size)
                ;
        // 评论列表
        List<ApComment> apComments = mongoTemplate.find(query, ApComment.class);
        // 3. 检查用户是否登录
        ApUser user = AppThreadLocalUtils.getUser();
        if(user == null || user.getId() == null){
            return ResponseResult.okResult(apComments);
        }
        // 4. 如果用户登录 , 需要判断当前评论中 哪些评论用户点过赞
       if(apComments!=null && apComments.size()>0){
           // 4.1 获取查询出来的评论ID列表  commentId in [ 1 , 3 ,5 ]   and authorId = [4]
           List<String> commentIdList = apComments.stream().map(ApComment::getId).collect(Collectors.toList());
           // 4.2 根据评论ID列表 及 当前登录用户ID 去mongo点赞集合查询
           Query findLikeQuery = Query.query(Criteria.where("commentId").in(commentIdList).and("authorId").is(user.getId()));
           // 4.3 得到当前评论列表中  我点过赞的信息
           List<ApCommentLike> apCommentLikes = mongoTemplate.find(findLikeQuery, ApCommentLike.class);
            // 点过赞的评论ID
           Set<String> myCommentIds = apCommentLikes.stream().map(ApCommentLike::getCommentId).collect(Collectors.toSet());
           // 将每一条评论转成vo对象， 如果是我评论过的需要将operation字段设置为0
           List<ApCommentVo> commentVoList = apComments.stream().map(comment -> {
               ApCommentVo commentVo = new ApCommentVo();
               BeanUtils.copyProperties(comment, commentVo);
               // 查看我所点过赞的评论中 是否包含当前评论ID
               if (myCommentIds.contains(comment.getId())) {
                   // 如果包含将operation设置为0
                   commentVo.setOperation((short) 0);
               }
               return commentVo;
           }).collect(Collectors.toList());
           return ResponseResult.okResult(commentVoList);
       }
       return ResponseResult.okResult(apComments);
    }
}
